
#include <libxml/encoding.h>
#include <libxml/xmlwriter.h>
#include <libxml/parser.h>
#include <json-glib/json-glib.h>
#include <json-glib/json-gobject.h>
#include <ctype.h>
void *json2xml__object(void *json, void *xml)
{
  xmlNodePtr xml_parent = xml, xml_node = NULL;
  JsonNode *node = json;

  int type = json_node_get_node_type(node);
  if (type == JSON_NODE_OBJECT) {
    if (!xml_parent) {
      //xml_parent = xmlNewNode(NULL, BAD_CAST "doc");
    }
    JsonObject *json_obj = json_node_get_object(node);
    JsonObjectIter iter;
    json_object_iter_init(&iter, json_obj);
    const char *member_name;
    JsonNode *member_node;
    while (json_object_iter_next(&iter, &member_name, &member_node)) {
      xml_node = xmlNewNode(NULL, BAD_CAST member_name);
      if (xml_parent) {
        xmlAddChild(xml_parent, xml_node);
      }
    //  printf("create node %s\n", member_name);
      json2xml__object(member_node, xml_node);
    }
  } else if (type == JSON_NODE_ARRAY) {
    /*
    JsonArray *json_arr = json_node_get_array(node);
    guint array_len = json_array_get_length(json_arr);
    for (guint i = 0; i < array_len; i++) {
      JsonNode *arr_item = json_array_get_element(json_arr, i);
      json2xml__object(arr_item, );
    }
    */
  } else if (type == JSON_NODE_VALUE) {
    if (json_node_get_value_type(node) == G_TYPE_STRING) {
      const char *value = json_node_get_string(node);
      xmlNodeSetContent(xml_parent, BAD_CAST value);
      //printf("set content:%s\n", value);
    } else if (json_node_get_value_type(node) == G_TYPE_INT) {
 //     printf("%ld\n", json_node_get_int(node));
    }
  }
  if (xml_parent) {
    return xml_parent;
  } else if (xml_node) {
    return xml_node;
  }
  return NULL;
}
char *json2xml__string(const char *src)
{
  int rc;
  char *res;//, *str;
  xmlNodePtr xml_node;

  JsonParser *parser = json_parser_new ();;
  JsonNode *node = NULL;

  json_parser_load_from_data(parser, src, -1, NULL);
  node = json_parser_get_root(parser);
  xml_node = json2xml__object(node, NULL);
  g_object_unref(parser);

  xmlBufferPtr xmlbuf = NULL;
  xmlbuf = xmlBufferCreate();
  rc = xmlNodeDump(xmlbuf, NULL, xml_node, 1, 1);
  if (rc == -1) {
    g_warning("xmlnodedump error\n");
  } else {
    xmlChar *str = xmlbuf->content;
    res = calloc(1, strlen((char *)str));
    strcpy(res, (char *)str);
    //printf("res:\n%s\n", res);
  }
  if (xmlbuf)
    xmlBufferFree(xmlbuf);
  xmlFreeNode(xml_node);
  return res;
}
char *json2xml__string_doc(const char *src)
{
  xmlChar *res;//, *str;
  xmlDocPtr doc;
  xmlNodePtr xml_node;

  JsonParser *parser = json_parser_new ();;
  JsonNode *node = NULL;

  json_parser_load_from_data(parser, src, -1, NULL);
  doc = xmlNewDoc(BAD_CAST XML_DEFAULT_VERSION);
  node = json_parser_get_root(parser);
  xml_node = json2xml__object(node, NULL);
  xmlDocSetRootElement(doc, xml_node);
  g_object_unref(parser);

  int len;
  xmlDocDumpMemoryEnc(doc, &res, &len, "UTF-8");
  xmlFreeDoc(doc);
  //xmlFreeNode(xml_node);
  return (char *)res;
}
int json2xml__file(const char *src, const char *dst)
{
  xmlChar *res;
  xmlNodePtr xml_node;
  xmlDocPtr doc;

  JsonParser *parser = json_parser_new ();;
  JsonNode *node = NULL;

  doc = xmlNewDoc(BAD_CAST XML_DEFAULT_VERSION);

  json_parser_load_from_mapped_file(parser, src, NULL);
  node = json_parser_get_root(parser);
  xml_node = json2xml__object(node, NULL);
  xmlDocSetRootElement(doc, xml_node);
  g_object_unref(parser);

  int len;
//  xmlDocDumpMemoryEnc(doc, &res, &len, "UTF-8");
  xmlDocDumpFormatMemoryEnc(doc, &res, &len, "UTF-8", 1);
  xmlFreeDoc(doc);
  FILE *fp = fopen(dst, "w");
  size_t size = fwrite((char *)res, 1, strlen((char *)res), fp);
  if (size) {
    printf("succeed:\n%s\n", (char *)res);
  }
  fclose(fp);
  xmlFreeNode(xml_node);
  xmlFree(res);
  return 0;
}
void *json_to_xml_object(void *json, void *xml)
{
  xmlNodePtr xml_parent = xml, xml_node = NULL;
  JsonNode *node = json;

  int type = json_node_get_node_type(node);
  if (type == JSON_NODE_OBJECT) {
    if (!xml_parent) {
      xml_parent = xmlNewNode(NULL, BAD_CAST "dev");
    }
    JsonObject *json_obj = json_node_get_object(node);
    JsonObjectIter iter;
    json_object_iter_init(&iter, json_obj);
    const char *member_name;
    JsonNode *member_node;
    while (json_object_iter_next(&iter, &member_name, &member_node)) {
      if (json_node_get_node_type(member_node) == JSON_NODE_VALUE) {
        if (json_node_get_value_type(member_node) == G_TYPE_STRING) {
          const char *value = json_node_get_string(member_node);
          xmlNewProp(xml_parent, BAD_CAST member_name, BAD_CAST value);
          //printf("set content:%s\n", value);
        } else if (json_node_get_value_type(node) == G_TYPE_INT) {
     //     printf("%ld\n", json_node_get_int(node));
        }
      } else if (json_node_get_node_type(member_node) == JSON_NODE_ARRAY) {
        JsonArray *json_arr = json_node_get_array(member_node);
        guint array_len = json_array_get_length(json_arr);
        for (guint i = 0; i < array_len; i++) {
          JsonNode *arr_item = json_array_get_element(json_arr, i);
          xml_node = xmlNewNode(NULL, BAD_CAST member_name);
          xmlAddChild(xml_parent, xml_node);
          json_to_xml_object(arr_item, xml_node);
        }
      }
    //  printf("create node %s\n", member_name);
      json_to_xml_object(member_node, xml_parent);
    }
  } else if (type == JSON_NODE_ARRAY) {
  }
  if (xml_parent) {
    return xml_parent;
  } else if (xml_node) {
    return xml_node;
  }
  return NULL;
}
char *json_to_xml_str(const char *src)
{
  int rc;
  char *res;//, *str;
  xmlNodePtr xml_node;

  JsonParser *parser = json_parser_new ();;
  JsonNode *node = NULL;

  json_parser_load_from_data(parser, src, -1, NULL);
  node = json_parser_get_root(parser);
  xml_node = json_to_xml_object(node, NULL);
  g_object_unref(parser);

  xmlBufferPtr xmlbuf = NULL;
  xmlbuf = xmlBufferCreate();
//  rc = xmlNodeDump(xmlbuf, NULL, xml_node, 1, 1);
  rc = xmlNodeDump(xmlbuf, NULL, xml_node, 1, 0);
  if (rc == -1) {
    g_warning("xmlnodedump error\n");
  } else {
    xmlChar *str = xmlbuf->content;
    res = calloc(1, strlen((char *)str));
    strcpy(res, (char *)str);
    //printf("res:\n%s\n", res);
  }
  if (xmlbuf)
    xmlBufferFree(xmlbuf);
  xmlFreeNode(xml_node);
  return res;
}
